home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / rsxwdk2s.zip / RSXWDK / LIBSRC / WINIO / WINIO.C < prev    next >
C/C++ Source or Header  |  1995-01-17  |  31KB  |  1,043 lines

  1. /*
  2. WINIO.C
  3. Stdio (e.g. printf) functionality for Windows - implementation
  4. Dave Maxey - 1991
  5. revisions by Andrew Schulman - 1991
  6. originally in Microsoft Systems Journal, July 1991
  7. revised for use by article in MSJ, September 1991
  8.  
  9. *****
  10. changed for GNU C by Rainer Schnitker
  11.  
  12. */
  13.  
  14. #include <windows.h>
  15. #include <stdlib.h>
  16. #include <stdarg.h>
  17. #include <malloc.h>
  18. #include <string.h>
  19. #include "wmhandlr.h"
  20. #include "winio.h"
  21.  
  22. #ifdef __GNUC__
  23. #define _fmemcpy memcpy
  24. #define _fmemset memset
  25. #endif
  26.  
  27. /* PROTOTYPES in alphabetic order */
  28.  
  29. void        winio_addchars(BYTE *, unsigned);
  30. void        winio_adjust_caret(void);
  31. void        winio_append2buffer(BYTE *, unsigned);
  32. int        winio_chInput(void);
  33. void        winio_compute_repaint(void);
  34. int        winio_initialize_buffers(unsigned);
  35. int        winio_initialize_class(HANDLE);
  36. void        winio_initialize_state(void);
  37. int        winio_initialize_window(HANDLE, HANDLE, int);
  38. void        winio_make_avail(unsigned);
  39. BYTE far *    winio_nextline(BYTE far *);
  40. BYTE far *    winio_prevline(BYTE far *);
  41. void        winio_set_font(void);
  42. void        winio_settitle(BYTE *pchTitle);
  43. LRESULT     winio_wmpaint(HWND, UINT, WPARAM, LPARAM);
  44. LRESULT     winio_wmsize(HWND, UINT, WPARAM, LPARAM);
  45. LRESULT     winio_wmdestroy(HWND, UINT, WPARAM, LPARAM);
  46. LRESULT     winio_wmchar(HWND, UINT, WPARAM, LPARAM);
  47. LRESULT     winio_wmkeydown(HWND, UINT, WPARAM, LPARAM);
  48. LRESULT     winio_wmhscroll(HWND, UINT, WPARAM, LPARAM);
  49. LRESULT     winio_wmvscroll(HWND, UINT, WPARAM, LPARAM);
  50. LRESULT     winio_wmsetfocus(HWND, UINT, WPARAM, LPARAM);
  51. LRESULT     winio_wmkillfocus(HWND, UINT, WPARAM, LPARAM);
  52.  
  53. /* this doesn't get declared in stdio.h if _WINDOWS is defined */
  54. /* although it is in the Windows libraries! */
  55. #ifndef __GO32__
  56. int        vsprintf(char *, const char *, va_list);
  57. #else
  58. int             vsprintf(char *, const char *, ...);
  59. #endif
  60.  
  61. #define     winio_caret_visible() \
  62.         ((yCurrLine <= (yTopOfWin + yWinHeight)) && \
  63.         (xCurrPos <= (xLeftOfWin + xWinWidth)) && \
  64.         (xCurrPos >= xLeftOfWin))
  65.  
  66. #define     CHECK_INIT() if (! tWinioVisible) return FALSE
  67.  
  68. #define     MAX_X            127
  69. #define     TABSIZE         8
  70. #define     TYPE_AHEAD        256
  71. #define     WINIO_DEFAULT_BUFFER    8192
  72. #define     MIN_DISCARD        256
  73. #define     CARET_WIDTH        2
  74.  
  75. /* For scrolling procedures */
  76. #define     USE_PARAM        10000
  77. #define     DO_NOTHING        10001
  78.  
  79. static    BYTE        winio_class[15] = "winio_class";
  80. static    BYTE        winio_icon[15] = "winio_icon";
  81. static    BYTE        winio_title[128] = "Stdio Window";
  82. static    unsigned long    bufsize = WINIO_DEFAULT_BUFFER;
  83. static    unsigned long    kbsize = TYPE_AHEAD;
  84. static    unsigned    bufused, bufSOI;
  85. static    unsigned    curr_font = SYSTEM_FIXED_FONT;
  86. static    int        tWinioVisible = FALSE;
  87. static    int        tCaret = FALSE, tFirstTime = TRUE;
  88. static    int        cxChar, cyChar, cxScroll, cyScroll, cxWidth, cyHeight;
  89. static    int        xWinWidth, yWinHeight, xCurrPos;
  90. static    int        xLeftOfWin, yTopOfWin, yCurrLine;
  91. static    unsigned    pchKbIn, pchKbOut;
  92. static    BYTE far    *fpBuffer, far *fpTopOfWin, far *fpCurrLine;
  93. static    BYTE far    *fpKeyboard;
  94. static    HANDLE        hBuffer, hKeyboard;
  95. static    HWND        hwnd;
  96. static    BOOL        tTerminate = TRUE;
  97. static    BOOL        tPaint = TRUE;
  98. static    BOOL        tEcho = TRUE;
  99. static    DESTROY_FUNC    destroy_func;
  100. static    int        control_c = 0;
  101.  
  102. typedef struct {
  103.     int hSB, vSB;
  104.     } recVKtoSB;
  105.  
  106. /* This table defines, by scroll message, what increment to try */
  107. /* and scroll horizontally. PGUP and PGDN entries are updated    */
  108. /* in the winio_wmsize function.                */
  109. static int    cScrollLR[SB_ENDSCROLL + 1] =
  110. /*UP  DOWN PGUP     PGDN    POS        TRACK      TOP      BOT     ENDSCROLL */
  111. { -1, +1,  -1,        +1,     USE_PARAM, USE_PARAM, -MAX_X, MAX_X, DO_NOTHING};
  112.  
  113. /* This table defines, by scroll message, what increment to try */
  114. /* and scroll horizontally. PGUP and PGDN entries are updated    */
  115. /* in the winio_wmsize function, and the TOP & BOTTOM entries    */
  116. /* are updated by addchar function.                */
  117. static int    cScrollUD[SB_ENDSCROLL + 1] =
  118. /*UP  DOWN PGUP     PGDN    POS        TRACK      TOP      BOT     ENDSCROLL */
  119. { -1, +1,  -1,        +1,     USE_PARAM, USE_PARAM, -1,      +1,     DO_NOTHING};
  120.  
  121. /* This table associates horizontal and vertical scroll     */
  122. /* messages that should be generated by the arrow and page keys */
  123. static recVKtoSB VKtoSB[VK_DOWN - VK_PRIOR + 1] =
  124. /*            VK_PRIOR            VK_NEXT */
  125.         {   { DO_NOTHING, SB_PAGEUP },    { DO_NOTHING, SB_PAGEDOWN },
  126. /*            VK_END            VK_HOME */
  127.             { SB_TOP, SB_BOTTOM },    { SB_TOP, SB_TOP },
  128. /*            VK_LEFT            VK_UP */
  129.             { SB_LINEUP, DO_NOTHING },    { DO_NOTHING, SB_LINEUP },
  130. /*            VK_RIGHT            VK_DOWN */
  131.             { SB_LINEDOWN, DO_NOTHING },{ DO_NOTHING, SB_LINEDOWN } };
  132.  
  133. /* ===================================================================    */
  134. /* the interface functions themselves.....                */
  135. /* ===================================================================    */
  136.  
  137. int winio_fputchar(int c)
  138.     {
  139.     CHECK_INIT();
  140.     winio_addchars((BYTE *)&c, 1);
  141.     return c;
  142.     }
  143.  
  144. int winio_fgetchar(void)
  145.     {
  146.     int ch;
  147.     CHECK_INIT();
  148.     ch = winio_chInput();
  149.     if (tEcho)
  150.     winio_fputchar(ch);
  151.     return ch;
  152.     }
  153.  
  154. char *winio_gets(char *pchTmp)
  155.     {
  156.     char *pch = pchTmp;
  157.     int c;
  158.  
  159.     CHECK_INIT();
  160.     bufSOI = bufused; /* mark beginning of line to limit backspace */
  161.     do {
  162.     if ((c = winio_fgetchar()) == '\n')
  163.         c = '\0';
  164.     switch (c)
  165.         {
  166.         case '\b' :     if (pch > pchTmp) pch--; break;
  167.         case 0x03 :     winio_fputchar('^');
  168.                 winio_fputchar('C');
  169.                 winio_fputchar('\n');
  170.                 c=0; *pchTmp = 0; break;
  171.         case 0x1b :     pch = pchTmp; break;
  172.         case EOF :        bufSOI = -1; return NULL;
  173.         default :        *pch = (BYTE) c; pch++;
  174.         }
  175.     } while (c);
  176.     bufSOI = -1;
  177.     return pchTmp;
  178.     }
  179.  
  180. int winio_kbhit(void)
  181.     {
  182.     CHECK_INIT();
  183.     return (pchKbIn == pchKbOut);
  184.     }
  185.  
  186. int winio_puts(const char *s)
  187.     {
  188.     BYTE c = '\n';
  189.     CHECK_INIT();
  190.     winio_addchars((BYTE *) s, strlen(s));
  191.     winio_addchars(&c, 1);
  192.     return 0;
  193.     }
  194.  
  195. int winio_read_kbd(int echo, int wait, int signal)
  196.     {
  197.     int ch;
  198.     CHECK_INIT();
  199.     if (!wait && !winio_kbhit())
  200.     return -1;
  201.     ch = winio_chInput();
  202.     if (echo)
  203.     winio_fputchar(ch);
  204.     return ch;
  205.     }
  206.  
  207. int winio_get_controlc(void)
  208. {
  209.     int tmp = control_c ;
  210.     control_c = 0;
  211.     return tmp;
  212. }
  213.  
  214. /* ---------------------------------------------------------------  */
  215. /* USED INTERNALLY - pops up an error window and returns FALSE        */
  216. /* ---------------------------------------------------------------  */
  217. static int fail(BYTE *s)
  218.     {
  219.     MessageBox(NULL,s,"ERROR",MB_OK);
  220.     return FALSE;
  221.     }
  222.  
  223. /* ---------------------------------------------------------------  */
  224. /* pops up a message window                        */
  225. /* ---------------------------------------------------------------  */
  226. BOOL winio_warn(BOOL confirm, const BYTE *fmt, ...)
  227.     {
  228.     BYTE s[256];
  229.     va_list marker;
  230.  
  231.     va_start(marker, fmt);
  232.     vsprintf(s, fmt, marker);
  233.     va_end(marker);
  234.  
  235.     return (MessageBox(NULL, s, winio_title,
  236.     confirm? MB_OKCANCEL : MB_OK) == IDOK);
  237.     }
  238.  
  239. /* ---------------------------------------------------------------  */
  240. /* The application must call this function before using any of the  */
  241. /* covered stdio type calls. We need the parameter info in order    */
  242. /* to create the window. The function allocates the buffer and        */
  243. /* creates the window. It returns TRUE or FALSE.            */
  244. /* ---------------------------------------------------------------  */
  245. int winio_init(HANDLE hInstance, HANDLE hPrevInstance,
  246.         int nCmdShow, unsigned wBufSize)
  247.     {
  248.     if (tWinioVisible)
  249.     return FALSE;
  250.  
  251.     if (! winio_initialize_buffers(wBufSize))
  252.     return FALSE;
  253.  
  254.     winio_initialize_state();
  255.  
  256.     if (! winio_initialize_window(hInstance, hPrevInstance, nCmdShow))
  257.     return FALSE;
  258.  
  259.     tWinioVisible = TRUE;
  260.  
  261.     atexit(winio_end);    /* hook into exit chain */
  262.  
  263.     winio_yield();
  264.     return TRUE;
  265.     }
  266.  
  267. /* ---------------------------------------------------------------  */
  268. /* Clear the contents of the buffer.                    */
  269. /* ---------------------------------------------------------------  */
  270. void winio_clear(void)
  271.     {
  272.     _fmemset(fpBuffer,0,(int) bufsize - 1);
  273.     fpCurrLine = fpTopOfWin = fpBuffer;
  274.     *fpBuffer = '\0';
  275.     xCurrPos = 0;
  276.     yCurrLine = 0;
  277.     yTopOfWin = 0;
  278.     xLeftOfWin = 0;
  279.     bufused = 0;
  280.  
  281.     if (tWinioVisible)
  282.     {
  283.     SetScrollRange(hwnd, SB_VERT, 1, yCurrLine + 1, FALSE);
  284.     SetScrollPos(hwnd, SB_VERT, yTopOfWin + 1, TRUE);
  285.     }
  286.     }
  287.  
  288. /* ---------------------------------------------------------------  */
  289. /* Return the window handle of the underlying Windows object.        */
  290. /* Can be used by an application to customize the WINIO window        */
  291. /* ---------------------------------------------------------------  */
  292. HWND winio_hwnd(void)
  293.     {
  294.     return hwnd;
  295.     }
  296.  
  297. /* ---------------------------------------------------------------  */
  298. /* This function is called by winio_init(). It initializes a number */
  299. /* of global variables, including the WM_ handler table.        */
  300. /* ---------------------------------------------------------------  */
  301. void winio_initialize_state()
  302.     {
  303.     winio_clear();
  304.     destroy_func = 0;
  305.  
  306.     /* set up our message handlers */
  307.     wmhandler_init();
  308.     wmhandler_set(WM_PAINT,      winio_wmpaint);
  309.     wmhandler_set(WM_SIZE,      winio_wmsize);
  310.     wmhandler_set(WM_DESTROY,      winio_wmdestroy);
  311.     wmhandler_set(WM_CHAR,      winio_wmchar);
  312.     wmhandler_set(WM_HSCROLL,      winio_wmhscroll);
  313.     wmhandler_set(WM_VSCROLL,      winio_wmvscroll);
  314.     wmhandler_set(WM_SETFOCUS,      winio_wmsetfocus);
  315.     wmhandler_set(WM_KILLFOCUS,   winio_wmkillfocus);
  316.     wmhandler_set(WM_KEYDOWN,      winio_wmkeydown);
  317.     }
  318.  
  319. /* ---------------------------------------------------------------  */
  320. /* This function is called by winio_init(). It initializes our        */
  321. /* Windows class, and some global variables                */
  322. /* ---------------------------------------------------------------  */
  323. int winio_initialize_window(HANDLE hInst, HANDLE hPrev, int nCmdShow)
  324.     {
  325.     static RECT start;
  326.     int cx, cy, inc;
  327.  
  328.     cx = GetSystemMetrics(SM_CXSCREEN);
  329.     cy = GetSystemMetrics(SM_CYSCREEN);
  330.     inc = GetSystemMetrics(SM_CYCAPTION);
  331.     cxScroll = GetSystemMetrics(SM_CXVSCROLL);
  332.     cyScroll = GetSystemMetrics(SM_CYHSCROLL);
  333.  
  334.     if (hPrev)
  335.     {
  336.     /* note: other WINIO apps are NOT other instances! */
  337.     GetInstanceData(hPrev, (NPSTR) &start, sizeof(RECT));
  338.     start.top += inc;
  339.     start.left += inc;
  340.     if (start.top > (cy >> 2))
  341.         start.top = cy >> 3;
  342.     if (start.left > (cx >> 2))
  343.         start.left = cx >> 3;
  344.     }
  345.     else
  346.     {
  347.     if (! winio_initialize_class(hInst))
  348.         return fail("Could not create class");
  349.  
  350.     start.left = inc;
  351.     start.right = cx - 4 * inc;
  352.     start.top = inc;
  353.     start.bottom = cy - 4 * inc;
  354.     }
  355.  
  356.     hwnd = CreateWindow(winio_class, NULL,
  357.     WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
  358.     start.left, start.top, start.right, start.bottom,
  359.     NULL, NULL, hInst, NULL);
  360.     if (! hwnd)
  361.     return fail("Could not create window");
  362.  
  363.     winio_set_font();
  364.  
  365.     /*
  366.     if (nCmdShow==SW_MINIMIZE)
  367.     nCmdShow=SW_SHOWMINIMIZED;
  368.       */
  369.  
  370.     ShowWindow(hwnd, nCmdShow);
  371.     UpdateWindow(hwnd);
  372.  
  373.     return TRUE;
  374.     }
  375.  
  376. /* -----------------------------------------------------------------------  */
  377. /* Initializes Window Class                            */
  378. /* -----------------------------------------------------------------------  */
  379. int winio_initialize_class(HANDLE hInst)
  380.     {
  381.     WNDCLASS  wc;
  382.  
  383.     wc.style = CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNCLIENT;
  384.     wc.lpfnWndProc = WndProc;
  385.     wc.cbClsExtra = 0;
  386.     wc.cbWndExtra = 0;
  387.     wc.hInstance = hInst;
  388.     wc.hIcon = LoadIcon(hInst, winio_icon);
  389.     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  390.     wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  391.     wc.lpszMenuName = NULL;
  392.     wc.lpszClassName = winio_class;
  393.  
  394.     return RegisterClass(&wc);
  395.     }
  396.  
  397. /* -----------------------------------------------------------------------  */
  398. /* Uses GlobalAlloc() to allocate the display and keyboard buffers        */
  399. /* -----------------------------------------------------------------------  */
  400. int winio_initialize_buffers(unsigned wBufSize)
  401.     {
  402.     if (wBufSize)
  403.     bufsize = max(wBufSize, 1024);
  404.  
  405.     if (! (hBuffer = GlobalAlloc(GMEM_MOVEABLE, bufsize)))
  406.     return fail("Could not allocate/nconsole I/O buffer");
  407.  
  408.     fpBuffer = GlobalLock(hBuffer); /* keep locked; assume protected mode */
  409.  
  410.     if (! (hKeyboard = GlobalAlloc(GMEM_MOVEABLE, kbsize)))
  411.     return fail("Could not allocate/type ahead buffer");
  412.  
  413.     fpKeyboard = GlobalLock(hKeyboard);
  414.  
  415.     *fpBuffer = '\0';
  416.     fpBuffer++;
  417.  
  418.     return TRUE;
  419.     }
  420.  
  421. /* -----------------------------------------------------------------------  */
  422. /* Undoes the work of the above. Allows an application to close the window  */
  423. /* Terminates the prog.                             */
  424. /* -----------------------------------------------------------------------  */
  425. void winio_yield2();
  426. void winio_end()
  427.     {
  428.     winio_settitle("inactive");
  429.     while (tWinioVisible == TRUE)
  430.     winio_yield();
  431.     }
  432.  
  433. /* -------------------------------------------------------------------    */
  434. /* Closes the window by sending it a WM_DESTROY message. Note that it    */
  435. /* does not disable the _onclose defined function. So the user program    */
  436. /* handler will be triggered. Does NOT cause the app. to terminate.    */
  437. /* -------------------------------------------------------------------    */
  438. void winio_close()
  439.     {
  440.     tTerminate = FALSE;
  441.     DestroyWindow(hwnd);
  442.     tTerminate = TRUE;
  443.     }
  444.  
  445. /* -------------------------------------------------------------------    */
  446. /* processes any outstanding events waiting. These may be characters    */
  447. /* typed at the keyboard, WM_PAINT messages, etc. It is called        */
  448. /* internally but should also be used liberally by the application    */
  449. /* within loops.                            */
  450. /* -------------------------------------------------------------------    */
  451. void winio_yield()
  452. {
  453.     MSG msg;
  454.     if (! tWinioVisible)    /* CHECK_INIT() */
  455.     return;
  456.  
  457.     while (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) {
  458.     TranslateMessage(&msg);
  459.     DispatchMessage(&msg);
  460.     }
  461. }
  462.  
  463. void winio_yield2()
  464. {
  465.     MSG msg;
  466.  
  467.     if (! tWinioVisible)    /* CHECK_INIT() */
  468.     return;
  469.     if (InSendMessage())    /* chech deadlock */
  470.     return;
  471.  
  472.     for (;;) {
  473.     if (! GetMessage(&msg, NULL, 0, 0))
  474.         break;
  475.     TranslateMessage(&msg);
  476.     DispatchMessage(&msg);
  477.     if (! PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
  478.         break;
  479.     }
  480. }
  481.  
  482.  
  483. /* -------------------------------------------------------------------    */
  484. /* Let the application install an exit routine, called back from    */
  485. /* winio_wmdestroy(). Deinstall by winio_onclose(NULL)            */
  486. /* -------------------------------------------------------------------    */
  487. void winio_onclose(DESTROY_FUNC exitfunc)
  488.     {
  489.     destroy_func = exitfunc;
  490.     }
  491.  
  492. /* -------------------------------------------------------------------    */
  493. /* This function allows the font of the window to be modified, and may    */
  494. /* be used BEFORE winio_init. Currently, only SYSTEM_, ANSI_, and    */
  495. /* OEM_FIXED_FONTs are supported.                    */
  496. /* -------------------------------------------------------------------    */
  497. BOOL winio_setfont(WORD wFont)
  498.     {
  499.     if ((wFont != SYSTEM_FIXED_FONT) &&
  500.     (wFont != ANSI_FIXED_FONT) &&
  501.     (wFont != OEM_FIXED_FONT))
  502.     return FALSE;
  503.     curr_font = wFont;
  504.     if (tWinioVisible)
  505.     {
  506.     winio_set_font();
  507.     if (tPaint)
  508.         InvalidateRect(hwnd, NULL, TRUE);
  509.     }
  510.     return TRUE;
  511.     }
  512.  
  513. /* -------------------------------------------------------------------    */
  514. /* This function allows the title of the window to be modified, and may */
  515. /* be used BEFORE winio_init.                        */
  516. /* -------------------------------------------------------------------    */
  517. void winio_settitle(BYTE *pchTitle)
  518.     {
  519.     strncpy(winio_title, pchTitle, 127);
  520.     winio_title[127] = '\0';
  521.     if (tWinioVisible)
  522.     SetWindowText(hwnd, winio_title);
  523.     }
  524.  
  525. /* -------------------------------------------------------------------    */
  526. /* This function allows the caller to specifiy immediate or deferred    */
  527. /* screen updates. The call may not be issued before winio_init().    */
  528. /* -------------------------------------------------------------------    */
  529. BOOL winio_setpaint(BOOL on)
  530.     {
  531.     BOOL ret = tPaint;
  532.  
  533.     CHECK_INIT();
  534.     if (tPaint == on)
  535.     InvalidateRect(hwnd, NULL, TRUE);
  536.     return ret;
  537.     }
  538.  
  539. /* -------------------------------------------------------------------    */
  540. /* This function changes the behavior of getchar(), whose default    */
  541. /* is to echo characters, unlike DOS. winio_setecho(FALSE) restores    */
  542. /* the non-echo DOS behavior.                        */
  543. /* -------------------------------------------------------------------    */
  544. BOOL winio_setecho(BOOL flag)
  545.     {
  546.     BOOL ret = tEcho;
  547.     tEcho = flag;
  548.     return ret;
  549.     }
  550.  
  551. /* ---------------------------------------------------------------  */
  552. /* Our WM_PAINT handler. It sends the currrent 'in view' piece of   */
  553. /* the buffer to the window. Note that an embedded NULL character   */
  554. /* signifies an end of line, not '\n'.                              */
  555. /* ---------------------------------------------------------------  */
  556. LRESULT winio_wmpaint(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  557.     {
  558.     HDC hdc;
  559.     PAINTSTRUCT ps;
  560.     BYTE far *pchSOL = fpTopOfWin;
  561.     BYTE far *pchEOL;
  562.     int i, j, xStart;
  563.     int xLeft, xRight, yTop, yBottom;
  564.  
  565.     hdc = BeginPaint(hwnd, &ps);
  566.  
  567.     xLeft = (ps.rcPaint.left / cxChar) + xLeftOfWin;
  568.     xRight = (ps.rcPaint.right / cxChar) + xLeftOfWin;
  569.     yTop = ps.rcPaint.top / cyChar;
  570.     yBottom = ps.rcPaint.bottom / cyChar;
  571.     SelectObject(hdc, GetStockObject(curr_font));
  572.  
  573.     for (i = 0; i < yTop; i++)        /* lines above repaint region */
  574.     {
  575.     while (*pchSOL)
  576.         pchSOL++;
  577.     pchSOL++;
  578.     }
  579.  
  580.     if (i <= yCurrLine) /* something needs repainting.. */
  581.     {
  582.     for (i = yTop; i <= yBottom; i++)   /* lines in repaint region */
  583.         {
  584.         for (j = 0; (j < xLeft) && (*pchSOL); j++, pchSOL++)
  585.         ; /* Scroll right */
  586.         pchEOL = pchSOL;
  587.         xStart = j - xLeftOfWin;
  588.         for (j = 0; (*pchEOL) ; j++, pchEOL++) ; /* end of line */
  589.         TextOut(hdc, cxChar * xStart, cyChar * i, pchSOL,
  590.             min(j, xRight - xLeft + 2));
  591.         if ((unsigned)(pchEOL - fpBuffer) >= bufused)
  592.         break;
  593.         pchSOL = ++pchEOL;
  594.         }
  595.     }
  596.  
  597.     EndPaint(hwnd, &ps);
  598.     winio_adjust_caret();
  599.     return 0;
  600.     }
  601.  
  602. /* ---------------------------------------------------------------  */
  603. /* Our WM_SIZE handler. It updates the internal record of our        */
  604. /* window size, minus the scroll bars, and recalcs the scroll bar   */
  605. /* ranges.                                */
  606. /* ---------------------------------------------------------------  */
  607. LRESULT winio_wmsize(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  608.     {
  609.     cxWidth = LOWORD(lParam);
  610.     cyHeight = HIWORD(lParam);
  611.  
  612.     xWinWidth    = (cxWidth - cxScroll ) / cxChar;
  613.     yWinHeight    = (cyHeight - cyScroll ) / cyChar;
  614.  
  615.     cScrollLR[SB_PAGEUP]    = -xWinWidth / 2;
  616.     cScrollLR[SB_PAGEDOWN]  = +xWinWidth / 2;
  617.     cScrollUD[SB_PAGEUP]    = -yWinHeight + 1;
  618.     cScrollUD[SB_PAGEDOWN]  = +yWinHeight - 1;
  619.  
  620.     SetScrollRange(hwnd, SB_HORZ, 1, MAX_X, FALSE);
  621.     SetScrollPos(hwnd, SB_HORZ, xLeftOfWin + 1, TRUE);
  622.  
  623.     SetScrollRange(hwnd, SB_VERT, 1, yCurrLine + 1, FALSE);
  624.     SetScrollPos(hwnd, SB_VERT, yTopOfWin + 1, TRUE);
  625.  
  626.     return 0;
  627.     }
  628.  
  629. /* ---------------------------------------------------------------  */
  630. /* Our WM_DESTROY handler. It frees up storage associated with the  */
  631. /* window, and resets its state to uninitialized.            */
  632. /* ---------------------------------------------------------------  */
  633. LRESULT winio_wmdestroy(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  634.     {
  635.     if (destroy_func)
  636.     (*destroy_func)();
  637.     GlobalUnlock(hBuffer);
  638.     GlobalUnlock(hKeyboard);
  639.     GlobalFree(hBuffer);
  640.     GlobalFree(hKeyboard);
  641.     tWinioVisible = FALSE;
  642.     if (tTerminate) {
  643.     exit(0);
  644.     PostQuitMessage(0);
  645.     }
  646.     return 0;
  647.     }
  648.  
  649. /* --------------------------------------------------------------- */
  650. /* Our WM_BYTE handler. It adds the BYTE to the internal kb buffer */
  651. /* if there is room otherwise it queues a BEEP               */
  652. /* --------------------------------------------------------------- */
  653. LRESULT winio_wmchar(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  654.     {
  655.     BYTE far *lpchKeybd = fpKeyboard;
  656.     unsigned pchSave = pchKbIn;
  657.  
  658.     pchKbIn++;
  659.     if (pchKbIn == TYPE_AHEAD)
  660.     pchKbIn = 0;
  661.     if (pchKbIn == pchKbOut)
  662.     {
  663.     MessageBeep(0);
  664.     pchKbIn = pchSave;
  665.     }
  666.     else {
  667.     *(lpchKeybd + pchSave) = LOBYTE(wParam);
  668.     if (LOBYTE(wParam)==0x03)
  669.         control_c = 1;
  670.     }
  671.  
  672.     return 0;
  673.     }
  674.  
  675. /* ---------------------------------------------------------------  */
  676. /* Our WM_KEYDOWN handler. This handles what would be called        */
  677. /* function keys in the DOS world. In this case the function keys   */
  678. /* operate as scroll bar controls, so we generate messages to the   */
  679. /* scroll message handlers below.                    */
  680. /* ---------------------------------------------------------------  */
  681. LRESULT winio_wmkeydown(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  682.     {
  683.     int hSB, vSB;
  684.  
  685.     if ((wParam < VK_PRIOR) || (wParam > VK_DOWN))
  686.     return 0;
  687.  
  688.     hSB = VKtoSB[wParam - VK_PRIOR].hSB;
  689.     vSB = VKtoSB[wParam - VK_PRIOR].vSB;
  690.     if (hSB != DO_NOTHING)
  691.     SendMessage(hwnd, WM_HSCROLL, hSB, 0L);
  692.     if (vSB != DO_NOTHING)
  693.     SendMessage(hwnd, WM_VSCROLL, vSB, 0L);
  694.     return 0;
  695.     }
  696.  
  697. /* --------------------------------------------------------------- */
  698. /* Our WM_HSCROLL handler. It adjusts what part of the buffer       */
  699. /* is visible. It operates as left/right arrow keys.           */
  700. /* --------------------------------------------------------------- */
  701. LRESULT winio_wmhscroll(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  702.     {
  703.     int cxSave = xLeftOfWin,
  704.     xInc = cScrollLR[wParam];
  705.  
  706.     if (xInc == DO_NOTHING)
  707.     return 0;
  708.     else if (xInc == USE_PARAM)
  709.     xLeftOfWin = LOWORD(lParam) - 1;
  710.     else
  711.     xLeftOfWin += xInc;
  712.  
  713.     if ((xLeftOfWin = max(0, min(MAX_X - 1, xLeftOfWin))) == cxSave)
  714.     return 0;
  715.  
  716.     ScrollWindow(hwnd, (cxSave - xLeftOfWin) * cxChar, 0, NULL, NULL);
  717.     SetScrollPos(hwnd, SB_HORZ, xLeftOfWin + 1, TRUE);
  718.     UpdateWindow(hwnd);
  719.  
  720.     return 0;
  721.     }
  722.  
  723. /* --------------------------------------------------------------- */
  724. /* Our WM_VSCROLL handler. It adjusts what part of the buffer       */
  725. /* is visible. It operates as page and line up/down keys.       */
  726. /* --------------------------------------------------------------- */
  727. LRESULT winio_wmvscroll(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  728.     {
  729.     int cySave = yTopOfWin,
  730.     yInc = cScrollUD[wParam],
  731.     i;
  732.  
  733.     if (yInc == DO_NOTHING)
  734.     return 0;
  735.     else if (yInc == USE_PARAM)
  736.     yTopOfWin = LOWORD(lParam) - 1;
  737.     else
  738.     yTopOfWin += yInc;
  739.  
  740.     if ((yTopOfWin = max(0, min(yCurrLine, yTopOfWin))) == cySave)
  741.     return 0;
  742.  
  743.     if (yTopOfWin > cySave)
  744.     for (i = cySave; i < yTopOfWin; i++)
  745.         fpTopOfWin = winio_nextline(fpTopOfWin);
  746.     else
  747.     for (i = cySave; i > yTopOfWin; i--)
  748.         fpTopOfWin = winio_prevline(fpTopOfWin);
  749.  
  750.     ScrollWindow(hwnd, 0, (cySave - yTopOfWin) * cyChar, NULL, NULL);
  751.     SetScrollPos(hwnd, SB_VERT, yTopOfWin + 1, TRUE);
  752.     UpdateWindow(hwnd);
  753.  
  754.     return 0;
  755.     }
  756.  
  757. /* ---------------------------------------------------------------  */
  758. /* Our WM_SETFOCUS handler. It sets up the text caret.            */
  759. /* ---------------------------------------------------------------  */
  760. LRESULT winio_wmsetfocus(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  761.     {
  762.     CreateCaret(hwnd, NULL, CARET_WIDTH, cyChar);
  763.  
  764.     if ((tCaret = winio_caret_visible()))
  765.     {
  766.     SetCaretPos((xCurrPos - xLeftOfWin) * cxChar,
  767.             (yCurrLine - yTopOfWin) * cyChar);
  768.     ShowCaret(hwnd);
  769.     }
  770.  
  771.     return 0;
  772.     }
  773.  
  774. /* ---------------------------------------------------------------  */
  775. /* Our WM_KILLFOCUS handler. It destroys the text caret.        */
  776. /* ---------------------------------------------------------------  */
  777. LRESULT winio_wmkillfocus(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  778.     {
  779.     if (tCaret)
  780.     {
  781.     HideCaret(hwnd);
  782.     tCaret = FALSE;
  783.     }
  784.     DestroyCaret();
  785.     return 0;
  786.     }
  787.  
  788. void winio_set_font(void)
  789.     {
  790.     HDC hdc;
  791.     TEXTMETRIC tm;
  792.  
  793.     hdc = GetDC(hwnd);
  794.     SelectObject(hdc, GetStockObject(curr_font));
  795.     GetTextMetrics(hdc,&tm);
  796.     ReleaseDC(hwnd,hdc);
  797.     cxChar = tm.tmAveCharWidth;
  798.     cyChar = tm.tmHeight+tm.tmExternalLeading;
  799.     xWinWidth    = (cxWidth - cxScroll ) / cxChar;
  800.     yWinHeight    = (cyHeight - cyScroll ) / cyChar;
  801.     }
  802.  
  803. /* ---------------------------------------------------------------  */
  804. /* Adjusts the position of the caret, and shows or hides it, as     */
  805. /* appropriate.                             */
  806. /* ---------------------------------------------------------------  */
  807. void winio_adjust_caret()
  808.     {
  809.     int t = winio_caret_visible();
  810.  
  811.     if (t)
  812.     SetCaretPos((xCurrPos - xLeftOfWin) * cxChar,
  813.             (yCurrLine - yTopOfWin) * cyChar);
  814.     if (t && (! tCaret))
  815.     ShowCaret(hwnd);
  816.     if ((! t) && tCaret)
  817.     HideCaret(hwnd);
  818.     tCaret = t;
  819.     }
  820.  
  821. /* ---------------------------------------------------------------  */
  822. /* Computes, on the basis of what has just been updated, what area  */
  823. /* of the window needs to be repainted.                 */
  824. /* ---------------------------------------------------------------  */
  825. void winio_compute_repaint(void)
  826.     {
  827.     RECT rc;
  828.     static int xCP = 0, yCL = 0;
  829.     int tWholeWin = FALSE;
  830.  
  831.     if (yCurrLine > (yTopOfWin + yWinHeight))
  832.     {
  833.     yTopOfWin = 0;
  834.     fpTopOfWin = fpBuffer;
  835.     while (yTopOfWin < (yCurrLine - ((yWinHeight + 1) / 2)))
  836.         {
  837.         fpTopOfWin = winio_nextline(fpTopOfWin);
  838.         yTopOfWin++;
  839.         }
  840.     tWholeWin = TRUE;
  841.     }
  842.  
  843.     if ((xCurrPos < xLeftOfWin) || (xCurrPos > (xLeftOfWin + xWinWidth)))
  844.     {
  845.     xLeftOfWin = 0;
  846.     while (xLeftOfWin < (xCurrPos - ((xWinWidth + 1) / 2)))
  847.         xLeftOfWin++;
  848.     tWholeWin = TRUE;
  849.     }
  850.  
  851.     if (tWholeWin)
  852.     InvalidateRect(hwnd, NULL, TRUE);
  853.     else
  854.     {
  855.     rc.left = ((yCL == yCurrLine) ?
  856.         (min(xCP, xCurrPos) - xLeftOfWin) * cxChar : 0);
  857.     rc.top = (yCL - yTopOfWin) * cyChar;
  858.     rc.right = (xWinWidth + 1) * cxChar;
  859.     rc.bottom = (yCurrLine - yTopOfWin + 1) * cyChar;
  860.     InvalidateRect(hwnd, &rc, TRUE);
  861.     }
  862.  
  863.     yCL = yCurrLine;
  864.     xCP = xCurrPos;
  865.     }
  866.  
  867. /* ---------------------------------------------------------------  */
  868. /* Adds the supplied cch-long string to the display buffer, and     */
  869. /* ensures any changed part of the window is repainted.         */
  870. /* ---------------------------------------------------------------  */
  871. void winio_addchars(BYTE *pch, unsigned cch)
  872.     {
  873.     int ycSave = yCurrLine;
  874.     int ytSave = yTopOfWin;
  875.     int xSave = xLeftOfWin;
  876.  
  877.     winio_make_avail(cch);
  878.  
  879.     winio_append2buffer(pch, cch);
  880.  
  881.     if (ycSave != yCurrLine)
  882.     SetScrollRange(hwnd, SB_VERT, 1, yCurrLine + 1, FALSE);
  883.  
  884.     if (! tPaint)
  885.     return;
  886.  
  887.     winio_compute_repaint();
  888.  
  889.     cScrollUD[SB_TOP]        = -yCurrLine;
  890.     cScrollUD[SB_BOTTOM]    = yCurrLine;
  891.     if (ytSave != yTopOfWin)
  892.     SetScrollPos(hwnd, SB_VERT, yTopOfWin + 1, TRUE);
  893.  
  894.     if (xSave != xLeftOfWin)
  895.     SetScrollPos(hwnd, SB_HORZ, xLeftOfWin + 1, TRUE);
  896.  
  897.     winio_yield();
  898.     }
  899.  
  900. /* ---------------------------------------------------------------  */
  901. /* Add chars onto the display buffer, wrapping at end of line,        */
  902. /* expanding tabs, etc.                         */
  903. /* ---------------------------------------------------------------  */
  904. void winio_append2buffer(BYTE *pch, unsigned cch)
  905.     {
  906.     unsigned i;
  907.  
  908.     for (i = 0; i < cch; i++, pch++)
  909.     {
  910.     switch (*pch)
  911.         {
  912.         case '\n' :
  913.         *pch = '\0';
  914.         *(fpBuffer + bufused) = '\0';
  915.         bufused++;
  916.         fpCurrLine = fpBuffer + bufused;
  917.         yCurrLine++;
  918.         xCurrPos = 0;
  919.         bufSOI = bufused;
  920.         break;
  921.         case '\t' :
  922.         do  {
  923.             *(fpBuffer + bufused) = ' ';
  924.             bufused++;
  925.             xCurrPos++;
  926.             } while ((xCurrPos % TABSIZE) != 0);
  927.         break;
  928.         case EOF :
  929.         break;
  930.         case '\b' :
  931.         if (bufused > bufSOI)
  932.             {
  933.             bufused--;
  934.             xCurrPos--;
  935.             }
  936.         break;
  937.         case 0x1b :
  938.         while (bufused > bufSOI)
  939.             {
  940.             bufused--;
  941.             xCurrPos--;
  942.             }
  943.         break;
  944.         case 0x07 :
  945.         MessageBeep(0);
  946.         break;
  947.         default :
  948.         if (*pch > 0x1a)
  949.             {
  950.             if (xCurrPos >= MAX_X)
  951.             {
  952.             *(fpBuffer + bufused) = '\0';
  953.             bufused++;
  954.             xCurrPos = 0;
  955.             yCurrLine++;
  956.             fpCurrLine = fpBuffer + bufused;
  957.             }
  958.             xCurrPos++;
  959.             *(fpBuffer + bufused) = *pch;
  960.             bufused++;
  961.             }
  962.         }
  963.     }
  964.  
  965.     *(fpBuffer + bufused) = '\0'; /* '\0' terminator after end of buffer */
  966.     }
  967.  
  968. /* ---------------------------------------------------------------  */
  969. /* If we have run out of room in the display buffer, drop whole     */
  970. /* lines, and move the remaining buffer up.                */
  971. /* ---------------------------------------------------------------  */
  972. void winio_make_avail(unsigned cch)
  973.     {
  974.     unsigned cDiscard = 0;
  975.     BYTE far *fpTmp;
  976.     unsigned i;
  977.  
  978.     if ((unsigned long)(bufused + cch + TABSIZE) < bufsize)
  979.     return;
  980.  
  981.     fpTmp = fpBuffer;
  982.     cDiscard = ((max(MIN_DISCARD, cch + 1) + MIN_DISCARD - 1)
  983.     / MIN_DISCARD)        /* this gives a whole number of */
  984.     * MIN_DISCARD;        /* our allocation units. */
  985.     fpTmp += (LONG) cDiscard;
  986.     fpTmp = winio_nextline(fpTmp);
  987.     cDiscard = fpTmp - fpBuffer;
  988.     _fmemcpy(fpBuffer, fpTmp, bufused - cDiscard + 1);
  989.     bufused -= cDiscard;
  990.     if ((int) bufSOI != -1) bufSOI -= cDiscard;
  991.     fpTmp = fpBuffer + (LONG) bufused;
  992.     for (i = 0; i < cDiscard; i++) *fpTmp++ = '\0';
  993.     fpCurrLine = fpBuffer;
  994.     xCurrPos = yCurrLine = 0;
  995.     for (i = 0; i < bufused; i++)
  996.     {
  997.     if (*fpCurrLine)
  998.         xCurrPos++;
  999.     else
  1000.         {
  1001.         xCurrPos = 0;
  1002.         yCurrLine++;
  1003.         }
  1004.     fpCurrLine++;
  1005.     }
  1006.     xLeftOfWin = yTopOfWin = -9999;
  1007.  
  1008.     InvalidateRect(hwnd, NULL, TRUE);
  1009.     }
  1010.  
  1011.  
  1012. /* -------------------------------------------------------------------    */
  1013. /* These two routines find the beginning of the next, and previous    */
  1014. /* lines relative to their input pointer                */
  1015. /* -------------------------------------------------------------------    */
  1016.  
  1017. BYTE far *winio_nextline(BYTE far *p) { while (*p) p++; return ++p; }
  1018. BYTE far *winio_prevline(BYTE far *p) { p--; do p--; while (*p); return ++p; }
  1019.  
  1020. /* -------------------------------------------------------------------    */
  1021. /* Waits for a character to appear in the keyboard buffer, yielding    */
  1022. /* while nothing is available. Then inserts it into the buffer.     */
  1023. /* -------------------------------------------------------------------    */
  1024. int winio_chInput(void)
  1025.     {
  1026.     BYTE far *lpchKeyBd;
  1027.     BYTE c;
  1028.  
  1029.     CHECK_INIT();
  1030.     while (pchKbIn == pchKbOut)
  1031.     winio_yield();
  1032.  
  1033.     lpchKeyBd = fpKeyboard;
  1034.     c = *(lpchKeyBd + pchKbOut);
  1035.  
  1036.     pchKbOut++;
  1037.     if (pchKbOut == TYPE_AHEAD)
  1038.     pchKbOut = 0;
  1039.  
  1040.     /* Do CR/LF and EOF translation */
  1041.     return (c == 0x1a) ? EOF : (c == '\r') ? '\n' : c;
  1042.     }
  1043.